package com.pay.weixin.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 * Created by ThreeManTeam on 2016/2/16.
 */
public class HttpClientHelper {

    //连接池线程最大数量
    private static final int MAX_THREAD_COUNT = 50;

    //单个路由最大的连接线程数量
    private static final int MAX_ROUTE_THREAD_COUNT = 5;

    //默认请求超时时长，毫秒。
    private static final int DEFAULT_REQUEST_TIMEOUT = 30000;

    //默认请求连接超时时长，毫秒。
    private static final int DEFAULT_REQUEST_SOCKET_TIMEOUT = 33000;

    //默认用户代理。
    private static final String DEFAULT_USER_AGENT = "";

    private static HttpClientContext httpContext = null;

    private static CookieStore cookieStore = null;

    //创建httpclient实例
    private CloseableHttpClient httpClient = null;

    public CloseableHttpClient getHttpClient() {
        return httpClient;
    }

    public void setHttpClient(CloseableHttpClient httpClient) {
        this.httpClient = httpClient;
    }

    /**
     *
     * 私有的构造函数
     */
    private HttpClientHelper(){
        initHttpClient();
    }

    /**
     * 描述：创建httpClient连接池，并初始化httpclient
     */
    private void initHttpClient(){

        httpContext = HttpClientContext.create();
        Registry<CookieSpecProvider> registry = RegistryBuilder
                .<CookieSpecProvider> create()
                .register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
                .register(CookieSpecs.BROWSER_COMPATIBILITY,
                        new BrowserCompatSpecFactory()).build();
        httpContext.setCookieSpecRegistry(registry);
        httpContext.setCookieStore(cookieStore);

        //创建httpclient连接池
        PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
        //设置连接池线程最大数量
        httpClientConnectionManager.setMaxTotal(MAX_THREAD_COUNT);
        //设置单个路由最大的连接线程数量
        httpClientConnectionManager.setDefaultMaxPerRoute(MAX_ROUTE_THREAD_COUNT);
        //创建http request的配置信息
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(DEFAULT_REQUEST_TIMEOUT)
                .setSocketTimeout(DEFAULT_REQUEST_SOCKET_TIMEOUT)
                .build();

        //设置重定向策略
        LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();

        //初始化httpclient客户端
        httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)
                .setDefaultRequestConfig(requestConfig)
                .setUserAgent(DEFAULT_USER_AGENT)
                .setDefaultCookieStore(cookieStore)
                .setRedirectStrategy(redirectStrategy)
                .build();
    }

    /********单例模式声明开始********************/
    //类初始化时，自行实例化
    private static HttpClientHelper tmtHttpClient = null;
    /**
     * 描述：单例的静态方法
     * @return
     */
    public static synchronized HttpClientHelper getHttpClientInstance(){
        if (tmtHttpClient == null)
            tmtHttpClient = new HttpClientHelper();
        return tmtHttpClient;
    }

    /************************单例模式声明结束********/

    /**
     * 通过GET或POST方法下载数据。
     * @param httpRequest
     * @return
     */
    public TmtResult load(HttpUriRequest httpRequest){
        TmtResult tmtResult = null;
        CloseableHttpResponse response = null;
        try{
            //执行请求
            response = httpClient.execute(httpRequest);
            try {
                //获得响应的消息实体
                HttpEntity entity = response.getEntity();
                try {
                    //获取响应状态码
                    int statusCode = response.getStatusLine().getStatusCode();
                    //根据响应状态码进行处理
                    switch (statusCode) {
                        case 200:
                            byte[] contentBytes = EntityUtils.toByteArray(entity);
                            String content = new String(contentBytes, "UTF-8");
                            tmtResult = JsonHelper.fromJson(content, TmtResult.class, JSON.class);
                            break;
                        default:
                            String info = String.format("执行失败(请求结果码：%s", statusCode);
                            tmtResult = TmtResult.failure(info, null);
                            break;
                    }
                } finally {
                    //关闭httpEntity流
                    EntityUtils.consume(entity);
                }
            }finally {
                if (response != null)
                    response.close();
            }
        }catch (Exception ex){
            String info = String.format("执行异常：%s", ex.getMessage());
            tmtResult = TmtResult.failure(info, null);
        }
        return tmtResult;
    }

    public static TmtResult post(String url, JSONObject json) {
        StringEntity entity = new StringEntity(json.toString(), "UTF-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");

        HttpClientHelper helper = HttpClientHelper.getHttpClientInstance();
        HttpPost httpPost =  new HttpPost(url);

        httpPost.setEntity(entity);

        TmtResult result = helper.load(httpPost);

        return result;
    }

    public static TmtResult get(String url) {
        HttpClientHelper helper = HttpClientHelper.getHttpClientInstance();
        HttpGet httpGet =  new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");
        TmtResult result = helper.load(httpGet);
        return result;
    }



    private static void printResponse(HttpResponse httpResponse)
            throws ParseException, IOException {
        // 获取响应消息实体
        HttpEntity entity = httpResponse.getEntity();
        // 响应状态
        System.out.println("status:" + httpResponse.getStatusLine());
        System.out.println("headers:");
        HeaderIterator iterator = httpResponse.headerIterator();
        while (iterator.hasNext()) {
            System.out.println("\t" + iterator.next());
        }
        // 判断响应实体是否为空
        if (entity != null) {
            String responseString = EntityUtils.toString(entity);
            System.out.println("response length:" + responseString.length());
            System.out.println("response content:"
                    + responseString.replace("\r\n", ""));
        }
    }

}
